package com.info33.platform.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.info33.platform.business.app.dao.AppMenuRoleDao;
import com.info33.platform.business.app.dao.AppTenantMenuDao;
import com.info33.platform.business.app.dto.AppTenantApplyDTO;
import com.info33.platform.business.app.entity.AppMenuRole;
import com.info33.platform.business.app.entity.AppTenantApply;
import com.info33.platform.business.app.entity.AppTenantMenu;
import com.info33.platform.business.app.entity.AppTenantUser;
import com.info33.platform.business.app.service.AppTenantUserService;
import com.info33.platform.common.constant.AppConstant;
import com.info33.platform.common.constant.TableConstant;
import com.info33.platform.common.exception.TransactionalException;
import com.info33.platform.common.mvc.vo.Result;
import com.info33.platform.common.util.PasswordUtil;
import com.info33.platform.common.util.SysUtil;
import com.info33.platform.system.dao.*;
import com.info33.platform.system.dto.SysTenantDTO;
import com.info33.platform.system.dto.SysUserDTO;
import com.info33.platform.system.entity.*;
import com.info33.platform.system.service.SysMenuService;
import com.info33.platform.system.service.SysTenantService;
import com.info33.platform.system.util.enums.DeptTypeEnum;
import com.info33.platform.system.util.enums.UserTypeEnum;
import com.info33.platform.system.vo.SysMenuVO;
import com.info33.platform.system.vo.SysTenantMenuVO;
import com.info33.platform.system.vo.SysTenantVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author admin
 */
@Slf4j
@Service
@Transactional(rollbackFor = {Exception.class, Error.class})
public class SysTenantServiceImpl extends ServiceImpl<SysTenantDao, SysTenant> implements SysTenantService {

    @Autowired
    SysTenantDao sysTenantDao;

    @Autowired
    SysConfigDao sysConfigDao;

    @Autowired
    SysTenantMenuDao sysTenantMenuDao;

    @Autowired
    SysDeptDao sysDeptDao;

    @Autowired
    SysPostDao sysPostDao;

    @Autowired
    SysUserDao sysUserDao;

    @Autowired
    SysDeptPostDao sysDeptPostDao;

    @Autowired
    SysMenuUserDao sysMenuUserDao;

    @Autowired
    SysTenantUserDao sysTenantUserDao;

    @Autowired
    SysMenuService sysMenuService;

    @Autowired
    SysShortcutMenuDao sysShortcutMenuDao;

    @Autowired
    private AppTenantMenuDao appTenantMenuDao;
    @Autowired
    private AppTenantUserService appTenantUserService;
    @Autowired
    private AppMenuRoleDao appMenuRoleDao;
    @Autowired
    private SysAppTenantMenuDao sysAppTenantMenuDao;
    @Autowired
    private SysAppMenuRoleDao sysAppMenuRoleDao;

    @Autowired
    private Environment environment;

    @Override
    public Result<?> saveTenant(SysTenantDTO sysTenantDTO) {
        // 1.添加租户信息  sys_tenant
        if (!ObjectUtils.isEmpty(getOne(new QueryWrapper<SysTenant>().eq("url", sysTenantDTO.getUrl())))) {
            return Result.error("租户域名已存在");
        }
        SysTenant sysTenant = new SysTenant();
        BeanUtils.copyProperties(sysTenantDTO, sysTenant);
        if (save(sysTenant)) {
            //2.添加系统配置
            saveConfig(sysTenant, sysTenantDTO.getConfigList());
            //3.添加下发菜单信息
            saveTenantMenu(sysTenant, sysTenantDTO.getMenuList());
            //4.添加部门信息
            Long deptId = saveDept(sysTenant);
            //5.添加角色信息
            Long postId = savePost(sysTenant);
            //6.添加用户信息
            Long userId = saveUser(sysTenant, deptId, sysTenantDTO.getUserList());
            //7.添加用户-租户信息  sys_tenant_user
            Long tenantUserId = saveTenantUser(sysTenant, userId);
            //8.添加用户-部门-岗位  sys_dept_post
            saveDeptPost(sysTenant, deptId, postId, tenantUserId);
            //9.添加岗位-菜单信息 sys_menu_user
            saveMenuUser(sysTenant, postId);
            // 添加 app 菜单
            saveAppMenu(sysTenant, sysTenantDTO.getAppMenuIds(), sysTenantDTO.getUserList().get(0));
            // 添加 mapp 菜单
            saveSysAppMenu(sysTenant, sysTenantDTO.getSysAppMenuIds(), sysTenantDTO.getUserList().get(0));
            return Result.ok(sysTenant);
        }
        throw new TransactionalException("保存失败，请重试");
    }

    private void saveAppMenu(SysTenant sysTenant, List<Long> appMenuIds, SysUser sysUser) {
        if (ObjectUtils.isEmpty(appMenuIds)) {
            return;
        }
        if (appTenantMenuDao.insertList(appMenuIds, sysTenant.getId()) != appMenuIds.size()) {
            throw new TransactionalException();
        }
        if (ObjectUtils.isEmpty(sysUser)) {
            return;
        }
        // 有菜单，就得将此用户注册到这个租户 app 应用下
        SysUserDTO dto = new SysUserDTO();
        BeanUtils.copyProperties(sysUser, dto);
        appTenantUserService.register(dto, sysTenant.getId());
    }

    private void saveSysAppMenu(SysTenant sysTenant, List<Long> appMenuIds, SysUser sysUser) {
        if (ObjectUtils.isEmpty(appMenuIds)) {
            return;
        }
        if (sysAppTenantMenuDao.insertList(appMenuIds, sysTenant.getId()) != appMenuIds.size()) {
            throw new TransactionalException();
        }
    }

    /**
     * 添加系统配置信息
     *
     * @param sysTenant 租户信息
     * @param sysTenant 配置信息
     * @return
     */
    private void saveConfig(SysTenant sysTenant, List<SysConfig> configList) {
        for (SysConfig sysConfig : configList) {
            sysConfig.setCreateDate(new Date());
            sysConfig.setUpdateDate(new Date());
            sysConfig.setCreateBy(sysTenant.getCreateBy());
            sysConfig.setUpdateBy(sysTenant.getUpdateBy());
            sysConfig.setTenantId(sysTenant.getId());
        }
        if (sysConfigDao.batchInsert(configList) != configList.size()) {
            throw new TransactionalException();
        }
    }

    /**
     * 添加下发菜单信息
     *
     * @param sysTenant 租户信息
     * @return
     */
    private void saveTenantMenu(SysTenant sysTenant, List<SysTenantMenu> menuList) {
        for (SysTenantMenu sysTenantMenu : menuList) {
            sysTenantMenu.setCreateDate(new Date());
            sysTenantMenu.setUpdateDate(new Date());
            sysTenantMenu.setCreateBy(sysTenant.getCreateBy());
            sysTenantMenu.setUpdateBy(sysTenant.getUpdateBy());
            sysTenantMenu.setTenantId(sysTenant.getId());
        }
        if (sysTenantMenuDao.batchInsert(menuList) != menuList.size()) {
            throw new TransactionalException();
        }
    }

    /**
     * 添加部门信息(root部门)
     *
     * @param sysTenant 租户信息
     */
    private Long saveDept(SysTenant sysTenant) {
        SysDept sysDept = new SysDept();
        sysDept.setTenantId(sysTenant.getId());
        sysDept.setPid(0L);
        sysDept.setType(DeptTypeEnum.COMPANY);
        sysDept.setName(sysTenant.getName());
        sysDept.setDeptLevel(1);
        sysDept.setCreateDate(new Date());
        sysDept.setUpdateDate(new Date());
        sysDept.setCreateBy(sysTenant.getCreateBy());
        sysDept.setUpdateBy(sysTenant.getUpdateBy());
        if (sysDeptDao.insertDept(sysDept) == 1) {
            return sysDept.getId();
        }
        throw new TransactionalException();
    }

    /**
     * 添加岗位信息
     *
     * @param sysTenant 租户信息
     */
    private Long savePost(SysTenant sysTenant) {
        SysPost sysPost = new SysPost();
        sysPost.setTenantId(sysTenant.getId());
        sysPost.setName("管理员");
        sysPost.setIndexes(TableConstant.NEW_TENANT_INDEX);
        sysPost.setCreateDate(new Date());
        sysPost.setUpdateDate(new Date());
        sysPost.setCreateBy(sysTenant.getCreateBy());
        sysPost.setUpdateBy(sysTenant.getUpdateBy());
        if (sysPostDao.insertPost(sysPost) == 1) {
            return sysPost.getId();
        }
        throw new TransactionalException();
    }

    /**
     * 添加用户信息
     * 校验：用户表里只存在唯一登录用户，如果手机号已经存在则不新增
     *
     * @param sysTenant 租户信息
     * @param deptId    部门id
     * @return 原本是要添加多个用户，但目前只添加一个 admin
     */
    private Long saveUser(SysTenant sysTenant, Long deptId, List<SysUser> userList) {
        for (SysUser sysUser : userList) {
            String mobile = sysUser.getMobile();
            QueryWrapper<SysUser> queryWrapper = new QueryWrapper<SysUser>();
            queryWrapper.eq("mobile", mobile);
            SysUser user = sysUserDao.selectOne(queryWrapper);
            if (ObjectUtils.isEmpty(user)) {
                Map<String, String> map = PasswordUtil.passwordMd5(AppConstant.DEFAULT_PASSWORD);
                sysUser.setPassword(map.get("password"));
                sysUser.setSalt(map.get("salt"));
                sysUser.setCreateDate(new Date());
                sysUser.setUpdateDate(new Date());
                sysUser.setCreateBy(sysTenant.getCreateBy());
                sysUser.setUpdateBy(sysTenant.getUpdateBy());
                if (sysUserDao.insertSysUser(sysUser) == 1) {
                    return sysUser.getId();
                } else {
                    throw new TransactionalException();
                }
            } else {
                return user.getId();
            }
        }
        throw new TransactionalException();
    }

    /**
     * 添加用户岗位信息
     *
     * @param sysTenant 租户信息
     * @param deptId    部门id
     * @param postId    岗位id
     * @param userId    用户id
     * @return
     */
    private Long saveDeptPost(SysTenant sysTenant, Long deptId, Long postId, Long userId) {
        SysDeptPost sysDeptPost = new SysDeptPost();
        sysDeptPost.setTenantId(sysTenant.getId());
        sysDeptPost.setUserId(userId);
        sysDeptPost.setPostId(postId);
        sysDeptPost.setDeptId(deptId);
        sysDeptPost.setPrincipal(true);
        sysDeptPost.setCreateDate(new Date());
        sysDeptPost.setUpdateDate(new Date());
        sysDeptPost.setCreateBy(sysTenant.getCreateBy());
        sysDeptPost.setUpdateBy(sysTenant.getUpdateBy());
        if (sysDeptPostDao.insertDeptPost(sysDeptPost) == 1) {
            return sysDeptPost.getId();
        }
        throw new TransactionalException();
    }

    /**
     * 保存角色-菜单信息
     *
     * @param sysTenant 租户信息
     * @param roleId    角色id
     */
    private void saveMenuUser(SysTenant sysTenant, Long roleId) {
        //获取菜单id集合
        List<SysTenantMenu> list = sysTenantMenuDao.selectList(new QueryWrapper<SysTenantMenu>()
                .eq(TableConstant.TENANT_ID, sysTenant.getId()));

        List<SysMenuUser> menuUserList = new ArrayList<SysMenuUser>();
        //分配菜单权限
        for (SysTenantMenu sysTenantMenu : list) {
            SysMenuUser menuUser = new SysMenuUser();
            menuUser.setTenantId(sysTenant.getId());
            menuUser.setPostId(roleId);
            menuUser.setMenuId(sysTenantMenu.getId());
            menuUser.setType(2);
            menuUser.setCreateDate(new Date());
            menuUser.setUpdateDate(new Date());
            menuUser.setCreateBy(sysTenant.getCreateBy());
            menuUser.setUpdateBy(sysTenant.getUpdateBy());
            menuUserList.add(menuUser);
        }
        if (sysMenuUserDao.batchInsert(menuUserList) != menuUserList.size()) {
            throw new TransactionalException();
        }
    }

    /**
     * 保存租户-用户信息
     *
     * @param sysTenant 租户信息
     * @param userId    用户id
     * @return
     */
    private Long saveTenantUser(SysTenant sysTenant, Long userId) {
        SysTenantUser sysTenantUser = new SysTenantUser();
        sysTenantUser.setTenantId(sysTenant.getId());
        sysTenantUser.setUserId(userId);
        sysTenantUser.setUserType(UserTypeEnum.ADMIN);
        sysTenantUser.setCreateDate(new Date());
        sysTenantUser.setUpdateDate(new Date());
        sysTenantUser.setCreateBy(sysTenant.getCreateBy());
        sysTenantUser.setUpdateBy(sysTenant.getUpdateBy());
        if (sysTenantUserDao.insertTenantUser(sysTenantUser) == 1) {
            return sysTenantUser.getId();
        }
        throw new TransactionalException();
    }

    @Override
    public Result<?> updateTenant(@Valid SysTenantDTO sysTenantDTO) {
        // 1.编辑租户信息  sys_tenant
        SysTenant sysTenant = getOne(new QueryWrapper<SysTenant>()
                .eq("url", sysTenantDTO.getUrl())
                .ne(TableConstant.ID, sysTenantDTO.getId()));
        if (sysTenant != null) {
            return Result.error("租户域名已存在");
        }
        sysTenant = new SysTenant();
        BeanUtils.copyProperties(sysTenantDTO, sysTenant);
        if (updateById(sysTenant)) {
            //2.编辑下发菜单权限
            List<SysTenantMenu> menuListAdd = sysTenantDTO.getMenuListAdd();
            if (!CollectionUtils.isEmpty(menuListAdd)) {
                //新增租户-菜单
                saveTenantMenu(sysTenant, menuListAdd);
                //新增到角色菜单
                SysPost sysPost = sysPostDao.selectOne(new QueryWrapper<SysPost>().eq(TableConstant.TENANT_ID, sysTenant.getId())
                        .eq("indexes", TableConstant.NEW_TENANT_INDEX));
                //新增岗位-菜单
                saveMenuUser(sysTenant, sysPost.getId());
            }
            //获取删除菜单权限
            List<Long> menuIdDelete = sysTenantDTO.getMenuIdDelete();
            if (!CollectionUtils.isEmpty(menuIdDelete)) {
                //删除对应角色菜单
                sysMenuUserDao.deleteByMenuId(menuIdDelete);
                //删除快捷菜单
                sysShortcutMenuDao.deleteByMenuId(menuIdDelete);
                //删除租户菜单
                sysTenantMenuDao.deleteBatchIds(menuIdDelete);
            }
            // 判断是否需要操作 app 菜单
            if (Boolean.FALSE.equals(sysTenant.getHasApp())) {
                return Result.ok(sysTenant);
            }
            // 添加新增菜单
            if (!ObjectUtils.isEmpty(sysTenantDTO.getAppMenuIds())
                    && appTenantMenuDao.insertList(sysTenantDTO.getAppMenuIds(), sysTenant.getId()) != sysTenantDTO.getAppMenuIds().size()) {
                throw new TransactionalException();
            }
            // 删除掉菜单
            if (!ObjectUtils.isEmpty(sysTenantDTO.getAppMenuIdsRemove())) {
                if (appTenantMenuDao.delete(new QueryWrapper<AppTenantMenu>()
                        .in("menu_id", sysTenantDTO.getAppMenuIdsRemove())
                        .eq(TableConstant.TENANT_ID, sysTenant.getId()))
                        != sysTenantDTO.getAppMenuIdsRemove().size()) {
                    throw new TransactionalException();
                }
                // 删除菜单绑定的权限相关信息
                appMenuRoleDao.delete(new QueryWrapper<AppMenuRole>()
                        .in("menu_id", sysTenantDTO.getAppMenuIdsRemove())
                        .eq(TableConstant.TENANT_ID, sysTenant.getId()));
            }
            // 添加 mapp 新增菜单
            if (!ObjectUtils.isEmpty(sysTenantDTO.getSysAppMenuIds())
                    && sysAppTenantMenuDao.insertList(sysTenantDTO.getSysAppMenuIds(), sysTenant.getId()) != sysTenantDTO.getSysAppMenuIds().size()) {
                throw new TransactionalException();
            }
            // 删除掉 mapp 菜单
            if (!ObjectUtils.isEmpty(sysTenantDTO.getSysAppMenuIdsRemove())
                    && sysAppTenantMenuDao.delete(new QueryWrapper<SysAppTenantMenu>()
                    .in("menu_id", sysTenantDTO.getSysAppMenuIdsRemove())
                    .eq(TableConstant.TENANT_ID, sysTenant.getId()))
                    != sysTenantDTO.getSysAppMenuIdsRemove().size()) {
                throw new TransactionalException();
            }
            return Result.ok(sysTenant);
        }
        throw new TransactionalException();
    }

    @Override
    public IPage<SysTenantVO> pageTenantList(IPage<SysTenantVO> page, SysTenant sysTenant) {
        return sysTenantDao.pageTenantList(page, sysTenant);
    }

    @Override
    public SysTenantVO getDetailById(Long id, Long tenantId) {
        SysTenant sysTenant = sysTenantDao.selectById(id);
        SysTenantVO sysTenantVO = new SysTenantVO();
        //租户信息
        BeanUtils.copyProperties(sysTenant, sysTenantVO);
        //租户用户信息
        List<SysUser> adminUserList = sysTenantUserDao.getAdminUserList(id, "ADMIN");
        sysTenantVO.setAdminUserList(adminUserList);
        //菜单树
        Integer operationType = 0;
        //下发菜单列表
        List<SysTenantMenuVO> tenantMenuList;
        if (UserTypeEnum.ADMIN.equals(sysTenant.getType())) {
            operationType = 1;
            tenantMenuList = sysTenantMenuDao.getAllMenu(id);
        } else {
            tenantMenuList = sysTenantMenuDao.getAllIssueMenu(id);
        }
        List<SysMenuVO> menuTree = sysMenuService.getMenuTree(tenantId, operationType);
        sysTenantVO.setMenuTree(menuTree);

        sysTenantVO.setTenantMenuList(tenantMenuList);
        // 添加 app 菜单
        if (Boolean.TRUE.equals(sysTenant.getHasApp())) {
            sysTenantVO.setAppTenantMenuVOS(appTenantMenuDao.pcTree(sysTenant.getId()));
        }
        return sysTenantVO;
    }

    @Override
    public String devUrl(String url) {
        if (Boolean.TRUE.equals(SysUtil.isDev(environment))
                && ObjectUtils.isEmpty(sysTenantDao
                .selectOne(new QueryWrapper<SysTenant>()
                        .eq("url", url)
                        .last(TableConstant.LIMIT_ONE)))) {
            log.warn("目前为开发环境，此用户的域名不存在，现查询第一个域名为此用户使用");
            return sysTenantDao.selectById(1L).getUrl();
        }
        return url;
    }

    @Override
    public Result<Object> pcAgree(AppTenantApplyDTO dto, AppTenantApply old) {
        // 1.添加租户信息  sys_tenant
        if (!ObjectUtils.isEmpty(this.getOne(new QueryWrapper<SysTenant>()
                .eq("url", dto.getTenantDTO().getUrl())
                .last(TableConstant.LIMIT_ONE)))) {
            return Result.error("租户域名已存在");
        }
        SysTenant sysTenant = new SysTenant();
        BeanUtils.copyProperties(dto.getTenantDTO(), sysTenant);
        sysTenant.setInfo(old.getInfo());
        sysTenant.setName(old.getName());
        sysTenant.setType(UserTypeEnum.USER);
        if (Boolean.FALSE.equals(save(sysTenant))) {
            throw new TransactionalException("保存失败，请重试");
        }
        //2.添加系统配置
        saveConfig(sysTenant, dto.getTenantDTO().getConfigList());
        //3.添加下发菜单信息
        saveTenantMenu(sysTenant, dto.getTenantDTO().getMenuList());
        //4.添加部门信息
        Long deptId = saveDept(sysTenant);
        //5.添加角色信息
        Long postId = savePost(sysTenant);
        //7.添加用户-租户信息  sys_tenant_user
        Long tenantUserId = saveTenantUser(sysTenant, appTenantUserService.getOne(new QueryWrapper<AppTenantUser>()
                .select("user_id")
                .eq(TableConstant.ID, old.getCreateBy())
                .last(TableConstant.LIMIT_ONE)).getUserId());
        //8.添加用户-部门-岗位  sys_dept_post
        saveDeptPost(sysTenant, deptId, postId, tenantUserId);
        //9.添加岗位-菜单信息 sys_menu_user
        saveMenuUser(sysTenant, postId);
        // 添加 app 菜单
        saveAppMenu(sysTenant, dto.getTenantDTO().getAppMenuIds(), null);
        return Result.ok(sysTenant);
    }

}